﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Text;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;

namespace WorkFlowCore.Common.SimplePluginLoaders
{
    public static class SimplePluginLoader
    {

        /// <summary>
        /// 载入插件
        /// </summary>
        /// <typeparam name="TManifest"></typeparam>
        /// <param name="pluginDir"></param>
        /// <param name="loaded"></param>
        /// <returns></returns>
        public static void LoadPlugins<TManifest>(string pluginDir, Action<List<TManifest>> loaded) where TManifest : Manifest
        {
            var plugins = new List<TManifest>();

            var dirs = Directory.GetDirectories(pluginDir);
            foreach (var dir in dirs)
            {
                var manifestPath = Path.Combine(dir, "manifest.json");
                if (!File.Exists(manifestPath)) continue;
                try
                {
                    var manifest = JsonConvert.DeserializeObject<TManifest>(File.ReadAllText(manifestPath));
                    if (manifest == null) continue;

                    var context = new PluginAssemblyLoadContext(System.IO.Path.Combine(dir, "src", manifest.Entry));
                    var EntryLib = manifest.Entry;
                    var assembly = context.LoadFromAssemblyName(new System.Reflection.AssemblyName(EntryLib.Substring(0, EntryLib.Length - 4)));
                    manifest.Assembly = assembly;
                    plugins.Add(manifest);
                }
                catch (Exception ex)
                {
                    Console.Error.WriteLine($"{ex.Message},{ex}");
                    //
                }

            }
            loaded?.Invoke(plugins);
        }


        /// <summary>
        /// 载入插件
        /// </summary>
        /// <typeparam name="TManifest"></typeparam>
        /// <param name="services"></param>
        /// <param name="pluginDir"></param>
        /// <param name="loaded"></param>
        /// <returns></returns>
        public static IServiceCollection LoadPlugins<TManifest>(this IServiceCollection services, string pluginDir, Action<List<TManifest>> loaded) where TManifest : Manifest
        {
            if (!Directory.Exists(pluginDir)) return services;

            LoadPlugins(pluginDir, loaded);

            return services;
        }

        public static IServiceCollection LoadPlugins(this IServiceCollection services, string pluginDir, Action<List<Manifest>> loaded) 
        {
            if (!Directory.Exists(pluginDir)) Directory.CreateDirectory(pluginDir);
            return LoadPlugins<Manifest>(services, pluginDir, loaded);
        }
    }
}
